package com.smartstate.autoMaticControl.service.impl;




import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.smartstate.autoMaticControl.constant.DeviceTypeEnum;
import com.smartstate.autoMaticControl.entity.*;
import com.smartstate.autoMaticControl.mapper.DeviceDisMapper;
import com.smartstate.autoMaticControl.service.DeviceDisService;
import com.smartstate.autoMaticControl.vo.AlarmVo;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;


import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


import javax.websocket.Session;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class DeviceDisServiceImpl  extends ServiceImpl<DeviceDisMapper, Equipment> implements DeviceDisService {


    @Autowired
    private DeviceDisMapper  deviceDisMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private Object lock = new Object();

    private AlarmVo alarmVo = new AlarmVo();

    private String deviceId;

    private String userId;

    private HashSet<String> set=new HashSet<>();

    private String deviceType;

    private Session session;

    public String getDeviceId(){
        return deviceId;
    }

    public void setDeviceId(String deviceId){
        this.deviceId = deviceId;
    }

    @Override
    public List<Equipment> getList(Equipment  equipment) {
        List<Equipment> Equipments = deviceDisMapper.getList(
                DeviceTypeEnum.DEHUMIDIFIER_TYPE.getValue(),
                DeviceTypeEnum.DUSTER_TYPE.getValue(),
                equipment.getType());
        return Equipments;
    }


    @Override
    public List<Equipment> getListByType(String  deviceName) {
        return deviceDisMapper.getListByType(deviceName);
    }

    @Override
    public Equipment getDeviceById(String id) {
        return deviceDisMapper.getDeviceById(id);
    }



    /**
     * 空调系统信息查询
     * @param equipment
     * @return
     */
    @Override
    public List<Equipment> ConditioningSystemAll(Equipment equipment) {
        List<Equipment> Equipments = deviceDisMapper.getConditioningSystemList(
                DeviceTypeEnum.NEW_TREND_TYPE.getValue(),
                DeviceTypeEnum.BLOWING_IN_TYPE.getValue(),
                DeviceTypeEnum.EXHAUST_AIR_TYPE.getValue(),
                equipment.getType());
        return Equipments;
    }

    /**
     * 纯水系统信息查询
     * @param equipment
     * @return
     */
    @Override
    public List<Equipment> PureWaterAll(Equipment equipment) {
        List<Equipment> Equipments = deviceDisMapper.getPureWaterAllList(
                DeviceTypeEnum.PURE_WATER_ONE_TYPE.getValue(),
                DeviceTypeEnum.PURE_WATER_TWO_TYPE.getValue(),
                DeviceTypeEnum.PURE_WATER_THREE_TYPE.getValue(),
                equipment.getType());
        return Equipments;
    }

    @Override
    public List<TreeNode> getTreeList(String objId) {
        List<TreeNode> treeList = deviceDisMapper.getTreeList(objId);
        for (TreeNode treeNode : treeList) {
            List<Equipment> treeEquipments = deviceDisMapper.getTreeEquipments(treeNode.getId());
            treeNode.setEquipment(treeEquipments);
        }
        return treeList;
    }

    /**
     * 获取rootNode
     * @return
     */
    @Override
    public String rootNode() {
        return deviceDisMapper.getRootNode();
    }

    /**
     * 增加自控设备报警信息
     * @param deviceId
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Async
    public synchronized void addAlarm(String deviceId) {
        alarmVo.setId(UUID.randomUUID().toString().replaceAll("-",""));
        String objId = deviceDisMapper.selectObjIdByDeviceId(deviceId);
        alarmVo.setObjId(objId);
        String setObjName = deviceDisMapper.getObjName(deviceId);
        alarmVo.setObjName(setObjName);
        alarmVo.setEName(deviceDisMapper.getDeviceById(deviceId).getName());
        //alarmVo.setAlarmStop("");
        //alarmVo.setAlarmValue("");//报警值
        //alarmVo.setAttributes("");//报警类型
        alarmVo.setAbnormaltime(new DateTime());//异常开始时间
        //alarmVo.setTags("设备离线");
        //alarmVo.setWay("");
        alarmVo.setDeviceId(deviceId);
        alarmVo.setType("离线");
        //alarmVo.setStopTime("");
        alarmVo.setState("2");
        alarmVo.setRemark("设备离线");
        alarmVo.setTypes("2");
        List<AlarmVo> alarmVoRelooks = deviceDisMapper.getAlarm(deviceId);
        if (alarmVoRelooks==null){
            deviceDisMapper.addAlarm(alarmVo);
        }
        for (AlarmVo alarmVoRelook : alarmVoRelooks) {
            if (alarmVoRelook!=null && alarmVoRelook.getState().equals("1")){
                deviceDisMapper.addAlarm(alarmVo);
            }
        }
    }

    /**
     * 返回除湿机数据
     * @param deviceKey
     * @return
     */
    @Override
    public HashMap<String, ArrayList<Dedusting>> getArefaction(String deviceKey) {
        //获取redis上除湿机的所有key
        Set<String> keys = redisTemplate.keys(deviceKey);
        //根据keys读取全部除湿机数据
        List<List> redisResult = redisTemplate.executePipelined(
                new RedisCallback<List>() {
                    // 自定义序列化
                    RedisSerializer keyS = redisTemplate.getKeySerializer();
                    @Override
                    public List doInRedis(RedisConnection redisConnection) throws DataAccessException {
                        for (String key : keys) {
                            redisConnection.hMGet(keyS.serialize(key),
                                    keyS.serialize("type"), keyS.serialize("neGaTive"), keyS.serialize("deviceId"),
                                    keyS.serialize("SPraying"), keyS.serialize("motorSpeed"));
                        }
                        return null;
                    }
                }, redisTemplate.getValueSerializer()); // 自定义序列化
        //将读取到的redis值转成list集合，redisResult里的集合数据为[[type, neGaTive, deviceId, SPraying, motorSpeed],...]
        List<Dedusting> dedustingList = redisResult.stream().map(item -> {
            Dedusting dedusting = new Dedusting();
            dedusting.setDeviceId(String.valueOf(item.get(2)));
            dedusting.setType(String.valueOf(item.get(0)));
            dedusting.setMotorSpeed((Integer) item.get(4));
            dedusting.setSPraying((Integer) item.get(3));
            dedusting.setNeGaTive((Integer) item.get(1));
            return dedusting;
        }).collect(Collectors.toList());
        //根据type分组
        Map<String, List<Dedusting>> collect = dedustingList.stream().collect(Collectors.groupingBy(Dedusting::getType));
        List<Dedusting> abnormalList = collect.get("异常");
        List<Dedusting> normalList = collect.get("正常");
        List<Dedusting> dedustings = new ArrayList<>();
        dedustings.addAll(abnormalList);
        dedustings.addAll(normalList);
        ArrayList<Dedusting> dedustings1 = new ArrayList<>();
        ArrayList<Dedusting> dedustings2 = new ArrayList<>();
        ArrayList<Dedusting> dedustings3 = new ArrayList<>();
        ArrayList<Dedusting> dedustings4 = new ArrayList<>();
        int i=0;
        for (Dedusting dedusting : dedustings) {
            if (i<7){
               dedustings1.add(dedusting);
               i++;
            }
            if (i>=7 && i<14){
                dedustings2.add(dedusting);
                i++;
            }
            if (i>=14 && i<21){
                dedustings3.add(dedusting);
                i++;
            }
            if (i>=21){
                dedustings4.add(dedusting);
                i++;
            }
        }
        HashMap<String, ArrayList<Dedusting>> map = new HashMap<>();
        map.put("概览一",dedustings1);
        map.put("概览二",dedustings2);
        map.put("概览三",dedustings3);
        map.put("概览四",dedustings4);
        return map;
    }

    /**
     * 判断redis是否存在type
     * @param type
     * @return
     */
    public boolean getResult(String type){
        for (String deviceId : set) {
            if (type.equals(deviceId)){
                return true;
            }
        }
        return false;
    }

}
